home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK2.toast / Development Kits (Disc 2) / ScriptX / Draggable ScriptX Folders / utils / memory / rammeter / meter.sx < prev    next >
Encoding:
Text File  |  1995-12-10  |  12.6 KB  |  519 lines  |  [TEXT/ttxt]

  1. --<<<
  2.  
  3. -- 
  4. -- RAM_O_METER
  5. -- Memory viewer
  6. -- Ross Nelson
  7. --
  8. -- This memory viewer shows the total amount of ScriptX object heap used.
  9. -- To try it out, build it with bldAll.sx.  Restart ScriptX, and load ram.sxt.
  10. -- You'll get a small window showing amount of memory currently in black,
  11. -- and a line showing the maximum reached in blue.
  12. -- To test it out, try typing this in the listener, which allocates a megabyte
  13. -- of memory:
  14. --    b := new bytestring initialsize:1000000
  15. -- To release this memory type  b := undefined.
  16.  
  17. module RamTool
  18.     uses ScriptX
  19.     
  20.     exports RamTool,
  21.             startupTool,
  22.             shutdownTool
  23. end
  24.  
  25. in module RamTool
  26.  
  27. --
  28. -- globals
  29. --
  30.  
  31. -- version checking
  32. global constant versionMajor := 0
  33. global constant versionMinor := 01
  34. global constant releaseLevel := "a"                -- a-alpha, b-beta, dev-development
  35.  
  36. global constant oneMeg := 1024 * 1024
  37. global constant numFrames := 20
  38. global constant aRedBrush := new Brush color:(new RGBcolor red:255 green:0 blue:0)
  39. global constant aBlueBrush := new Brush color:(new RGBcolor red:0 green:0 blue:255)
  40.  
  41. -- I know there's a bunch of globals but we're trying to be garbage free.
  42. global totalMemFn := totalHeapSpace
  43. global freeMemFn := totalFreeHeapSpace
  44. global originalFreeSystemSpace
  45. global originalTotalHeapSpace
  46. global lastTotal := 0
  47. global lastFree := 0
  48. global scaleMax := 0
  49. global lastMax := 0
  50. global theRange := 1 to (numFrames - 1)
  51. global resetNext := false
  52. global mdown := new MouseDownEvent
  53. global mup := new MouseUpEvent
  54.  
  55. -- forward
  56. global updateDisplay
  57. global doMouseDown
  58. global doMouseUp
  59.  
  60. --
  61. -- HashedLine
  62. --
  63. class HashedLine (TwoDShape)
  64. inst vars
  65.     nTicks
  66.     hashMarks
  67.     orientation
  68.     setvarsFn
  69.     drawFn
  70. end
  71.  
  72. -- target must be rectangle specifying height of line, width of top&bottom hash marks
  73. method init self {class HashedLine} #rest args #key nTicks:(4) orientation:(@vertical) -> (
  74.     self.nTicks := nTicks
  75.     self.orientation := orientation
  76.     self.hashMarks := new Array initialSize:(self.nTicks + 2)
  77.     apply nextMethod self args
  78.     )
  79.  
  80. method afterInit self {class HashedLine} #rest args -> (
  81.     apply nextMethod self args
  82.     generateHash self
  83.     
  84.     -- create closures so draw can be garbage free
  85.     local surface, clip, transform
  86.     self.setvarsFn := (s c t -> 
  87.         surface := s; clip := c; transform := t
  88.         )
  89.     self.drawFn := (hash z -> 
  90.         stroke surface hash clip transform blackBrush
  91.         )
  92.     )
  93.  
  94. method generateHash self {class HashedLine} #rest args -> (
  95.     local pos, width, height, chunk
  96.  
  97.     width := self.width
  98.     height := self.height
  99.     emptyOut self.hashMarks
  100.     if (self.orientation == @vertical) then (
  101.         pos := (width - 1) / 2
  102.         chunk := height / self.nTicks
  103.         self.hashMarks[1] := new line x1:pos x2:pos y1:0 y2:height
  104.         self.hashMarks[2] := new line x1:0 x2:width y1:(height - 1) y2:(height - 1)
  105.         self.hashMarks[3] := new line x1:0 x2:width y1:0 y2:0
  106.         height := chunk
  107.         for (self.nTicks - 1) do (
  108.             append self.hashMarks (new line x1:(pos - 1) x2:(pos + 2) y1:height y2:height)
  109.             height := height + chunk
  110.             )
  111.         )
  112.     else (
  113.         pos := (self.height - 1) / 2
  114.         -- NYI
  115.         )
  116.     )
  117.  
  118. method draw self {class HashedLine} surface clip -> (
  119.     nextMethod self surface clip
  120.     self.setvarsFn surface clip self.transform
  121.     foreach self.hashMarks self.drawFn 0
  122.     )
  123.  
  124. --
  125. -- ScaledRect
  126. --
  127. class ScaledRect (TwoDPresenter)
  128. inst vars
  129.     _value
  130.     valueMax
  131.     valueMin
  132.     fillRect
  133.     fillBrush
  134. end
  135.  
  136. method init self {class ScaledRect} #rest args #key range:(0 to 100) target: fill:(blackBrush) -> (
  137.     self.valueMax := range.upperBound
  138.     self.valueMin := range.lowerBound
  139.     self._value := 0
  140.     self.fillRect := new rect x2:0 y2:target.y2
  141.     self.fillBrush := fill
  142.     apply nextMethod self args
  143.     )
  144.  
  145. method get value self {class ScaledRect} -> (
  146.     return self._value
  147.     )
  148.  
  149. method set value self {class ScaledRect} val -> (
  150.     if (val > self.valueMax) do
  151.         val := self.valueMax
  152.     if (val < self.valueMin) do
  153.         val := self.valueMin
  154.     
  155.     self._value := val
  156.     self.fillRect.height := round (((val - self.valueMin) / (self.valueMax - self.valueMin)) * self.target.height)
  157.     self.fillRect.y1 := self.fillRect.y2 := self.target.y2
  158.     return val
  159.     )
  160.  
  161. method set height self {class ScaledRect} val -> (
  162.     nextMethod self val
  163.     self.fillRect.height := round (((val - self.valueMin) / (self.valueMax - self.valueMin)) * self.target.height)
  164.     self.fillRect.y1 := self.fillRect.y2 := self.target.y2
  165.     return val
  166.     )
  167.  
  168. method set width self {class ScaledRect} val -> (
  169.     self.fillRect.width := val
  170.     nextMethod self val
  171.     )
  172.  
  173. method draw self {class ScaledRect} surface clip -> (
  174.     nextMethod self surface clip
  175.     stroke surface self.fillRect clip self.transform self.fillBrush
  176.     fill surface self.fillRect clip self.transform self.fillBrush
  177.     )
  178.  
  179. --
  180. -- Memory functions
  181. --
  182. function totalSystemSpace -> originalFreeSystemSpace
  183.  
  184. function totalMemory -> originalFreeSystemSpace + originalTotalHeapSpace
  185.  
  186. function totalFreeMemory -> totalFreeSystemSpace() + totalFreeHeapSpace()
  187.  
  188. --
  189. -- RamTool
  190. -- class that implements tool
  191. --
  192. class RamTool (ToolContainer)
  193. inst vars
  194.     transient clock
  195.     transient cb
  196.     transient cbRate
  197.     transient window
  198.     transient shapes
  199.     transient displayMode
  200.     transient skipDup
  201. end
  202.  
  203. method afterLoading self {class RamTool} strm -> (
  204.     self.clock := self.cb := self.window := self.shapes := undefined
  205.     self.cbRate := 5
  206.     nextMethod self strm
  207.     )
  208.     
  209. -- NOTE:  Tool is not fully initialized after 'init' or
  210. -- 'afterLoading', the 'prepareToRun' function must be called first
  211. method prepareToRun self {class RamTool} -> (
  212.     self.clock := new Clock title:self
  213.     self.clock.rate := self.clock.scale := 1
  214.     
  215.     self.window := new Window type:@palette boundary:(new rect x2:200 y2:88) title:self
  216.     self.window.x := 80
  217.     self.window.y := 50
  218.     
  219.     mUp.device := mDown.device := new MouseDevice
  220.     mUp.presenter := mDown.presenter := self.window
  221.     mUp.authorData := mDown.authorData := self
  222.     mDown.eventReceiver := doMouseDown
  223.     mUp.eventReceiver := doMouseUp
  224.     addEventInterest mDown
  225.  
  226.     self.shapes := new Array initialSize:(numFrames + 2)
  227.     
  228.     self.displayMode := @heap
  229.     self.skipDup := true
  230.  
  231.     setupDisplay self
  232.     setupMenus self
  233.     updateDisplay self self.window self.shapes
  234.     show self.window
  235.     )
  236.  
  237. -- initialize menus
  238. method setupMenus self {class RamTool} -> (
  239.     local            menu, subMenu
  240.     
  241.     local fn setMemType tool opt val -> (
  242.         if (opt == @update) do
  243.             return if (val == tool.displayMode) then @enabledChecked else @enabled
  244.         
  245.         if (self.displayMode == val) do
  246.             return
  247.     
  248.         self.displayMode := val
  249.         resetNext := true
  250.         )
  251.  
  252.     local fn setCallback tool opt val -> (
  253.         if (opt == @update) do
  254.             if (tool.cbRate = val) then
  255.                 return @enabledChecked
  256.             else
  257.                 return @enabled
  258.  
  259.         cancel tool.cb
  260.         tool.cbRate := val
  261.         tool.cb := addPeriodicCallback tool.clock updateDisplay tool #(tool.window, tool.shapes) val
  262.         tool.cb.skipIfLate := true
  263.         )
  264.  
  265.     -- now build the menu
  266.     menu := new ToolMenu name:"Ramometer"
  267.  
  268.     append menu (new ToolMenuItem name:"Show" menuFunc:(t i o -> 
  269.         if (o == @update) do
  270.             return @enabled
  271.         show t.window
  272.         ))
  273.  
  274.     subMenu := new ToolMenu name:"Monitor"
  275.     append subMenu (new ToolMenuItem name:"Heap Memory" menuFunc:(t i o -> setMemType t o @heap))
  276.     append subMenu (new ToolMenuItem name:"System Memory" menuFunc:(t i o -> setMemType t o @system))
  277.     append subMenu (new ToolMenuItem name:"All Memory" menuFunc:(t i o -> setMemType t o @all))
  278.     append menu subMenu
  279.  
  280.     subMenu := new ToolMenu name:"Seconds between updates"
  281.     append subMenu (new ToolMenuItem name:"1" menuFunc:(t i o -> setCallback t o 1))
  282.     append subMenu (new ToolMenuItem name:"5" menuFunc:(t i o -> setCallback t o 5))
  283.     append subMenu (new ToolMenuItem name:"15" menuFunc:(t i o -> setCallback t o 15))
  284.     append subMenu (new ToolMenuItem name:"30" menuFunc:(t i o -> setCallback t o 30))
  285.     append subMenu (new ToolMenuItem name:"60" menuFunc:(t i o -> setCallback t o 60))
  286.     append menu subMenu
  287.  
  288.     append menu (new ToolMenuItem name:"Skip Duplicates" menuFunc:(t i o -> 
  289.         if (o == @update) do
  290.             return if (t.skipDup) then @enabledChecked else @enabled
  291.             
  292.         t.skipDup := not t.skipDup
  293.         ))
  294.  
  295.  
  296.     append self.systemMenuBar menu
  297.     menuChanged self.systemMenuBar
  298.     )
  299.  
  300. global highWater := 0
  301. global arglist := new array initialSize:2
  302.  
  303. fn updateDisplay tc win shapes -> (
  304.     local total, free, inUse, r, l
  305.  
  306.     total := totalMemFn()
  307.     free := freeMemFn()
  308.  
  309.     if (resetNext or (total > scaleMax)) do (
  310.         resetNext := false
  311.         cancel tc.cb
  312.         setupDisplay tc
  313.         total := totalMemFn()
  314.         free := freeMemFn()
  315.         )
  316.  
  317.     if (tc.skipDup) do
  318.         if ((free > (lastFree - 100)) and (free < (lastFree + 100))) do
  319.             return
  320.     
  321.     lastFree := free
  322.     setNth arglist 1 win
  323.     setNth arglist 2 shapes
  324.  
  325.     foreach theRange (ix args ->
  326.         local win := getNth args 1
  327.         local shapes := getNth args 2
  328.         local td := getNth shapes ix
  329.         local tdNext := getNth shapes (ix + 1)
  330.         
  331.         td.height := tdNext.height
  332.         td.y := win.height - td.height - 4
  333.         ) arglist
  334.     
  335.     highWater := total - freeMemFn()
  336.     inUse := highWater / scaleMax
  337.     r := getNth shapes numFrames
  338.     r.height := round (80 * inUse)
  339.     r.y := win.height - r.height - 4
  340.  
  341.     -- blue line
  342.     l := getNth shapes (numFrames + 1)
  343.     if (inUse > lastMax) do (
  344.         lastMax := inUse
  345.         l.y := r.y
  346.         )
  347.  
  348.     -- red line
  349.     l := getNth shapes (numFrames + 2)
  350.     if (total > lastTotal) do (
  351.         lastTotal := total
  352.         l.y := win.height - (round (80 * (total / scaleMax))) - 4
  353.         )
  354.     )
  355.  
  356. global textInfo := undefined
  357.  
  358. function doMouseDown tc evint ev -> (
  359.     local fromRed, fromBlue, mem
  360.  
  361.     addEventInterest mUp
  362.     fromBlue := abs (ev.localCoords.y - tc.shapes[numFrames + 1].y)
  363.     fromRed := abs (ev.localCoords.y - tc.shapes[numFrames + 2].y)
  364.     if (fromBlue < fromRed) then (
  365.         setDefaultAttr textInfo @brush aBlueBrush
  366.         mem := highWater
  367.         )
  368.     else (
  369.         setDefaultAttr textInfo @brush aRedBrush
  370.         mem := totalMemFn()
  371.         )
  372.     
  373.     mem := (mem / 1024) as Integer
  374.     textInfo.target := (mem as String) + "K"
  375.     textInfo.x := ev.localCoords.x
  376.     textInfo.y := ev.localCoords.y - 12
  377.     append tc.window textInfo
  378.     )
  379.  
  380. function doMouseUp tc evint ev -> (
  381.     removeEventInterest mUp
  382.     deleteOne tc.window textInfo
  383.     )
  384.  
  385. method setupDisplay self {class RamTool} -> (
  386.     local megs, scale, anchorX, anchorY, td
  387.     
  388.     emptyout self.window
  389.     emptyout self.shapes
  390.  
  391.     case self.displayMode of
  392.         @heap:    (
  393.             totalMemFn := totalHeapSpace
  394.             freeMemFn := totalFreeHeapSpace
  395.             self.window.name := "ScriptX Heap"
  396.             )
  397.         @system: (
  398.             totalMemFn := totalSystemSpace
  399.             freeMemFn := totalFreeSystemSpace
  400.             self.window.name := "ScriptX System"
  401.             )
  402.         @all:    (
  403.             totalMemFn := totalMemory
  404.             freeMemFn := totalFreeMemory
  405.             self.window.name := "ScriptX Memory"
  406.             )
  407.         end
  408.     
  409.     megs := if (self.displayMode == @heap) then
  410.         totalHeapSpace() + (2 * oneMeg)        -- to allow for expansion
  411.     else
  412.         totalMemory()
  413.     megs := 1 + (trunc (megs / oneMeg))
  414.  
  415.     scale := new HashedLine nTicks:megs target:(new rect x2:5 y2:80)
  416.     scale.x := 4
  417.     scale.y := 4
  418.     append self.window scale
  419.  
  420.     scaleMax := megs * oneMeg
  421.     lastTotal := 0
  422.     lastMax := 0
  423.  
  424.     td := new textpresenter boundary:(new rect x2:20 y2:12) target:(megs as String)
  425.     setDefaultAttr td @size 8
  426.     setDefaultAttr td @leading 0
  427.     td.x := 10
  428.     td.y := 0
  429.     append self.window td
  430.  
  431.     anchorX := 16
  432.     anchorY := self.window.height - 4
  433.     for i := 0 to (numFrames - 1) do (
  434.         td := new twodshape target:(new rect x2:8 y2:0) stroke:blackBrush fill:blackBrush
  435.         td.x := anchorX + (i * 8)
  436.         td.y := anchorY - td.height
  437.         append self.window td
  438.         append self.shapes td
  439.         )
  440.     
  441.     -- add another element to shapes array, line showing max position reached
  442.     td := new twodshape target:(new line x2:160 y2:0) stroke:aBlueBrush
  443.     td.x := anchorX
  444.     td.y := anchorY
  445.     append self.window td
  446.     append self.shapes td
  447.  
  448.     -- add another element to shapes array, line showing top
  449.     td := new twodshape target:(new line x2:160 y2:0) stroke:aRedBrush
  450.     td.x := anchorX
  451.     td.y := anchorY
  452.     append self.window td
  453.     append self.shapes td
  454.  
  455.     -- add support for mouse fn
  456.     textInfo := new textpresenter boundary:(new rect x2:40 y2:12) target:"" fill:whiteBrush stroke:blackBrush
  457.     setDefaultAttr textInfo @size 8
  458.     setDefaultAttr textInfo @leading 0
  459.  
  460.     -- setup callback
  461.     self.cb := addPeriodicCallback self.clock updateDisplay self #(self.window, self.shapes) self.cbRate
  462.     self.cb.skipIfLate := true
  463.     )
  464.  
  465. --
  466. -- MENU HANDLERS
  467. --
  468.  
  469. method toolAbout self { class RamTool } -> (
  470.     local str, dlg
  471.     
  472.     print "Ramometer"
  473.     )
  474.  
  475. method toolPrefs self { class RamTool } -> (
  476.     OK
  477.     )
  478.  
  479. method toolQuit self { class RamTool } -> (
  480.     threadCriticalUp()
  481.         if (self.cb !== undefined) do
  482.             cancel self.cb
  483.         if (self.clock !== undefined) do (
  484.             self.clock.rate := 0
  485.             self.clock := undefined
  486.             )
  487.         if (self.window !== undefined) do (
  488.             removeEventInterest mDown
  489.             hide self.window
  490.             emptyOut self.window
  491.             self.window := undefined
  492.             )
  493.     threadCriticalDown()
  494.     )
  495.  
  496.  
  497. --
  498. --  STARTUP
  499. --  startup action for title, must be compiled in this module
  500. --
  501. function startupTool tc -> (
  502.     local notifyFn
  503.     
  504.     originalFreeSystemSpace := totalFreeSystemSpace()
  505.     originalTotalHeapSpace := totalHeapSpace()
  506.     foreach tc (mod z -> load mod) 0
  507.     prepareToRun tc
  508.     )
  509.  
  510. --
  511. --  SHUTDOWN
  512. --  shutdown action for title, must be compiled in this module
  513. --
  514. function shutdownTool tc -> (
  515.     toolQuit tc
  516.     )
  517.  
  518. -->>>
  519.